package com.zhongen.wflow.workflow.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson2.JSONArray;
import com.zhongen.wflow.mapper.WflowModelsMapper;
import com.zhongen.wflow.workflow.bean.process.ProcessNode;
import com.zhongen.wflow.workflow.bean.process.form.Form;
import com.zhongen.wflow.workflow.bean.process.form.FormPerm;
import com.zhongen.wflow.workflow.bean.process.props.ApprovalProps;
import com.zhongen.wflow.workflow.bean.process.props.CcProps;
import com.zhongen.wflow.workflow.bean.process.props.RootProps;
import com.zhongen.wflow.workflow.bean.process.props.SubProcessProps;
import com.zhongen.wflow.workflow.service.FormService;
import com.zhongen.wflow.workflow.service.ProcessNodeCatchService;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : willian fu
 * @date : 2022/8/24
 */
@Service
public class FormServiceImpl implements FormService {

	@Autowired
	private ProcessNodeCatchService nodeCatchService;

	@Autowired
	private WflowModelsMapper modelsMapper;

	@Autowired
	private RuntimeService runtimeService;

	@Autowired
	private HistoryService historyService;

	@Override
	public Map<String, Object> getProcessInstanceFormData(String instanceId) {
		return historyService.createHistoricVariableInstanceQuery()
			.processInstanceId(instanceId)
			.variableNameLike("field%")
			.list()
			.stream()
			.collect(Collectors.toMap(HistoricVariableInstance::getVariableName, HistoricVariableInstance::getValue));
	}

	@Override
	public Map<String, Object> getProcessInstanceFormDataLike(String instanceId, String likeName) {
		return null;
	}

	@Override
	public Object getProcessInstanceFormDataSingle(String instanceId, String fieldName) {
		return null;
	}

	@Override
	public <T> T getProcessInstanceFormDataSingleByType(String instanceId, String fieldName, Class<T> clazz) {
		return null;
	}

	@Override
	public void updateInstanceFormData(String instanceId, Map<String, Object> formData) {
		Map<String, Object> dataMap = new HashMap<>();
		formData.forEach((k, v) -> {
			Object variable = runtimeService.getVariable(instanceId, k);
			// 做下比较，不同就修改
			if (Objects.isNull(variable) && Objects.nonNull(v) || !variable.equals(formData.get(k))) {
				dataMap.put(k, v);
			}
		});
		if (CollectionUtil.isNotEmpty(dataMap)) {
			runtimeService.setVariables(instanceId, dataMap);
		}
	}

	@Override
	public List<Form> filterFormByPermConfigForRoot(List<Form> forms, RootProps rootProps) {
		Map<String, FormPerm.PermEnum> permEnumMap = rootProps.getFormPerms()
			.stream()
			.collect(Collectors.toMap(FormPerm::getId, FormPerm::getPerm));
		return doFilterForm(forms, null, permEnumMap, FormPerm.PermEnum.E);
	}

	@Override
	public List<Form> getFormsByProcessCodeFilterPerm(String currentNode, String code) {
		// TODO 同一个人在不同节点的表单权限可能不一样，按最大权限过滤
		String formItems = modelsMapper.selectById(code).getFormItems();
		ProcessNode<?> node = nodeCatchService.getProcessNodeById(code, currentNode);
		List<FormPerm> formPerms = null;
		FormPerm.PermEnum defaultPerm = FormPerm.PermEnum.R;
		switch (node.getType()) {
			case ROOT:
				formPerms = ((RootProps) node.getProps()).getFormPerms();
				defaultPerm = FormPerm.PermEnum.E;
				break;
			case TASK:
			case APPROVAL:
				formPerms = ((ApprovalProps) node.getProps()).getFormPerms();
				break;
			case CC:
				formPerms = ((CcProps) node.getProps()).getFormPerms();
				break;
			case SUBPROC:
				formPerms = ((SubProcessProps) node.getProps()).getFormPerms();
				break;
			default:
				formPerms = Collections.emptyList();
				break;
		}
		// 转换map
		Map<String, FormPerm.PermEnum> permEnumMap = formPerms.stream()
			.collect(Collectors.toMap(FormPerm::getId, FormPerm::getPerm));
		FormPerm.PermEnum finalDefaultPerm = defaultPerm;
		// 过滤出有查看权限的表单
		return JSONArray.parseArray(formItems, Form.class).stream().peek(item -> {
			FormPerm.PermEnum perm = permEnumMap.getOrDefault(item.getId(), finalDefaultPerm);
			item.setPerm(perm);
		}).filter(item -> !FormPerm.PermEnum.H.equals(item.getPerm())).collect(Collectors.toList());
	}

	@Override
	public List<Form> filterFormAndDataByPermConfig(List<Form> forms, Map<String, Object> formData,
			ProcessNode<?> currentNode) {
		FormPerm.PermEnum defaultPerm = FormPerm.PermEnum.R;
		List<FormPerm> formPerms = Collections.emptyList();
		if (Objects.isNull(currentNode)) {
			return doFilterForm(forms, formData, Collections.emptyMap(), defaultPerm);
		}
		switch (currentNode.getType()) {
			case ROOT:
				formPerms = ((RootProps) currentNode.getProps()).getFormPerms();
				defaultPerm = FormPerm.PermEnum.E;
				break;
			case TASK:
			case APPROVAL:
				formPerms = ((ApprovalProps) currentNode.getProps()).getFormPerms();
				break;
			case SUBPROC:
				formPerms = ((SubProcessProps) currentNode.getProps()).getFormPerms();
				break;
			case CC:
				formPerms = ((CcProps) currentNode.getProps()).getFormPerms();
				break;
		}
		Map<String, FormPerm.PermEnum> permEnumMap = formPerms.stream()
			.collect(Collectors.toMap(FormPerm::getId, FormPerm::getPerm));
		return doFilterForm(forms, formData, permEnumMap, defaultPerm);
	}

	private List<Form> doFilterForm(List<Form> forms, Map<String, Object> formData,
			Map<String, FormPerm.PermEnum> permEnumMap, FormPerm.PermEnum defaultPerm) {
		return forms.stream().filter(form -> {
			if ("SpanLayout".equals(form.getName())) {
				form.setPerm(Objects.isNull(formData) ? FormPerm.PermEnum.E : FormPerm.PermEnum.R);
				JSONArray items = (JSONArray) form.getProps().get("items");
				form.getProps()
					.put("items", doFilterForm(items.toJavaList(Form.class), formData, permEnumMap, defaultPerm));
			}
			else if ("TableList".equals(form.getName())) {
				FormPerm.PermEnum formPerm = permEnumMap.getOrDefault(form.getId(), defaultPerm);
				if (FormPerm.PermEnum.H.equals(formPerm)) {
					// 去除对应数据
					Optional.ofNullable(formData).ifPresent(data -> data.remove(form.getId()));
					return false;
				}
				form.setPerm(formPerm);
				JSONArray items = (JSONArray) form.getProps().get("columns");
				form.getProps()
					.put("columns", doFilterForm(items.toJavaList(Form.class), formData, permEnumMap, defaultPerm));
			}
			else {
				FormPerm.PermEnum formPerm = permEnumMap.getOrDefault(form.getId(), defaultPerm);
				if (FormPerm.PermEnum.H.equals(formPerm)) {
					// 去除对应数据
					Optional.ofNullable(formData).ifPresent(data -> data.remove(form.getId()));
					return false;
				}
				form.setPerm(formPerm);
			}
			return true;
		}).collect(Collectors.toList());
	}

}
